#include "uart4.h"
extern void delay_ms(unsigned int ms);
// 初始化的函数
void hal_uart4_init(void)
{
    // 1. 使能GPIOB,GPIOG外设的时钟 RCC_MP_AHB4ENSETR[1][6] = 0b1
    RCC->MP_AHB4ENSETR = (0x1 << 1) | (0x1 << 6);
    // 2. 设置PB2, 和 PG11引脚为复用的功能 
            // GPIOB_MODER[5:4] = 0b10  GPIOG_MODER[23:22] = 0b10
    GPIOB->MODER &= (~(0x3 << 4));
    GPIOB->MODER |= (0x2 << 4);
    GPIOG->MODER &= (~(0x3 << 22));
    GPIOG->MODER |= (0x2 << 22);
    // 3. 设置PB2引脚为UART4_RX功能  GPIOB_AFRL[11:8] --> AF8 --> 0b1000
        // 设置PG11引脚为UART4_TX功能  GPIOG_AFRH[15:12] --> AF6 --> 0b0110
    GPIOB->AFRL &= ~(0xF << 8);
    GPIOB->AFRL |= (0x8 << 8);
    GPIOG->AFRH &= ~(0xF << 12);
    GPIOG->AFRH |= (0x6 << 12);
    // 4. 使能UART4外设的时钟  RCC_MP_APB1ENSETR[16] = 0b1 
    RCC->MP_APB1ENSETR = (0x1 << 16);
    // 5. 判断UART4串口是否使能，如果使能则禁止串口
    if (USART4->CR1 & (0x1 << 0)) {
        delay_ms(5000);  // 等待之前的串口的数据发送完成之后在禁止串口
        USART4->CR1 &= (~(0x1 << 0));  // 禁止串口的使能
    }   
    // 6. 设置数据位为8位的数据宽度 USART4_CR1[28][12] = 0b00
    USART4->CR1 &= (~(0x1 << 28));
    USART4->CR1 &= (~(0x1 << 12));
    // 7. 禁止校验位，不适用校验  USART4_CR1[10] = 0b0
    USART4->CR1 &= (~(0x1 << 10));
    // 8. 设置串口的采样率为16倍或者8倍，最终会影响波特率的计算  USART4_CR1[15]
    USART4->CR1 &= (~(0x1 << 15));
    // 9. 设置停止位的个数为1位  USART4_CR2[13:12] = 0b00
    USART4->CR2 &= (~(0x3 << 12));
    // 10. 设置串口时钟的分频寄存器 USART4_PRERC[3:0]  最终也会影响波特率的计算
            // usart_ker_ck 时钟源的频率等于 64MHz
    USART4->PRESC &= (~(0xF << 0));
    // 11. 设置串口的波特率为115200bps  USART4_BRR[15:0]
    USART4->BRR = 0x22B;
    // 12. 使能串口发送器  USART4_CR1[3] = 0x1
    USART4->CR1 |= (0x1 << 3);
    // 13. 使能串口接收器  USART4_CR1[2] = 0x1
    USART4->CR1 |= (0x1 << 2);
    // 12. 使能串口        USART4_CR1[0] = 0x1
    USART4->CR1 |= (0x1 << 0);
}

// 发送一个字节的函数
void hal_send_char(const char ch)
{
    // 1. 判断发送寄存器是否为空，如果为空发送下一个字节的数据，
    // 如果不为空等待发送数据寄存器为空。  USART4_ISR[7]
    while(!(USART4->ISR & (0x1 << 7)));
    // 2. 发送数据，向发送数据寄存器中写入数据 USART4_TDR[7:0]
    USART4->TDR = ch;
    if (ch == '\n')
        hal_send_char('\r');
}

// 发送字符串的函数 
void hal_send_string(const char *str)
{
    // 1. 调用发送字符的函数一个一个的发送，字符串的结尾为‘/0’
    while(*str != '\0') {
        hal_send_char(*str);
        str++;
    }
}

// 接收一个字符的函数
char hal_recv_char(void)
{
    char ch;
    // 1. 判断接收数据寄存器中是否有有效的数据，如果有数据则读取数据
    //   如果没有有效的数据，则等待有有效的数据之后在读取。 USART4_ISR[5]
    while(!(USART4->ISR & (0x1 << 5)));
    // 2. 从接收数据寄存器中读取数据到ch变量中   USART4_RDR[7:0]
    ch = (char)USART4->RDR;
    return ch;
}

// 接收一个字符串的函数

char  buffer[LEN] = {0};
char * hal_recv_string(char str[])
{
    // 1. 一个字符一个字符的接收，接收到之后将数据存到buffer缓冲区中，
    // 最多接收49，接收结束之后结尾需要补'\0'.
    // 接收的情况，一种时接收49个字符结束，另一种是按下enter键之后结束
    // enter键是一个字符'\r'.
    int i;
    for (i = 0; i < LEN - 1; i++) {
        buffer[i] = hal_recv_char();   // 接收一个字符存到缓冲区中
        hal_send_char(buffer[i]);  // 接收一个字符回显一个字符
        if(buffer[i] == '\r') {
            break;
        }
    }

    buffer[i] = '\0';  // 字符串的结尾补'\0'
    hal_send_char('\n');
    return buffer;
}